// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: xguo

#pragma once

#include <functional>
#include <memory>
#include <string>
#include <unordered_map>

#include "coin2/exchange/base/market/market_exchange_api.h"

namespace FIX {
class Message;
}

namespace coin2::exchange::base::order {
struct OrderExecution;
}

namespace coin2::exchange::base::symbology {
class IProduct;
class IProductHolder;
}  // namespace coin2::exchange::base::symbology

namespace coin2::exchange::deribit::api_order::fix {

constexpr auto SPACE = ' ';
constexpr auto MARKET = '1';
constexpr auto LIMIT = '2';
constexpr auto STOP_LIMIT = '4';
constexpr auto BUY = '1';
constexpr auto SELL = '2';
constexpr auto GOOD_TILL_CANCEL = '1';
constexpr auto IMMEDIATE_OR_CANCEL = '3';
constexpr auto FILL_OR_KILL = '4';
constexpr auto POST_ONLY = 'P';
constexpr auto EMPTY = "";

using IProduct = coin2::exchange::base::symbology::IProduct;
using IProductHolder = coin2::exchange::base::symbology::IProductHolder;
using GetProductHolderFunc =
    std::function<const IProductHolder*(const IProduct& product, int64_t timestamp)>;

/********************************************************************************
 * struct DeribitOrder                                                              *
 ********************************************************************************/
struct DeribitOrder {
  using OrderExecution = coin2::exchange::base::order::OrderExecution;
  using MarketExchangeApi = coin2::exchange::base::market::MarketExchangeApi;

  std::string client_id;
  std::string symbol;
  char type;
  double quantity;
  double price;
  double cash_order_qty;
  double stop_price;
  char side;
  char time_in_force;
  std::string exec_inst;

  std::unordered_map<std::string, double> contract_value_map_;

  explicit DeribitOrder(
      const OrderExecution&,
      const MarketExchangeApi& mea,
      GetProductHolderFunc get_product_holder,
      double contract_multiplier);
  void Parse(
      const OrderExecution&,
      const MarketExchangeApi& mea,
      GetProductHolderFunc get_product_holder,
      double contract_multiplier);
  void Validate() const;
};

/********************************************************************************
 * class FixMessageBuilder                                                      *
 ********************************************************************************/
class FixMessageBuilder {
 public:
  using RequestTypePtr = std::unique_ptr<FIX::Message>;
  using OrderExecution = coin2::exchange::base::order::OrderExecution;

  explicit FixMessageBuilder(const MarketExchangeApi& mea) : mea_{mea} {}
  ~FixMessageBuilder() = default;
  FixMessageBuilder(const FixMessageBuilder&) = delete;
  FixMessageBuilder& operator=(const FixMessageBuilder&) = delete;

  RequestTypePtr GeneratePlaceOrder(
      const OrderExecution& ord_exec,
      GetProductHolderFunc get_product_holder,
      double contract_multiplier);
  RequestTypePtr GenerateCancelOrder(const OrderExecution& ord_exec);
  RequestTypePtr GenerateSecurityListRequest();

 private:
  const MarketExchangeApi& mea_;
};

}  // namespace coin2::exchange::deribit::api_order::fix
